﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Messaging;
using System.Data.Common;

namespace BrightFrame.Aop
{
    public sealed class TransactionAop : IMessageSink
    {
        private IMessageSink _nextSink;

        public TransactionAop(IMessageSink nextSink)
        {
            _nextSink = nextSink;
        }
        /// <summary>
        /// 用于异步处理
        /// </summary>
        /// <param name="msg"></param>
        /// <param name="replySink"></param>
        /// <returns></returns>
        public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
        {
            throw new NotImplementedException();
        }

        public IMessageSink NextSink
        {
            get { return _nextSink; }
        }

        public static string ConnectionName
        {
            get
            {
                return "Connection";
            }
        }

        public IMessage SyncProcessMessage(IMessage msg)
        {
            IMessage retMsg = null;

            IMethodCallMessage call = msg as IMethodCallMessage;

            object obj = CallContext.GetData(ConnectionName);
            if (obj != null)
            {
                using (DbConnection connection = obj as DbConnection)
                {
                    connection.Open();

                    TransactionMethodAttribute attribute = Attribute.GetCustomAttribute(call.MethodBase, typeof(TransactionMethodAttribute)) as TransactionMethodAttribute;
                    if (call == null || attribute == null)
                    {
                        retMsg = _nextSink.SyncProcessMessage(msg);
                    }
                    else
                    {
                        DbTransaction dbTransaction;
                        if(attribute.IsolationLevel == 0)
                            dbTransaction = connection.BeginTransaction();
                        else
                            dbTransaction = connection.BeginTransaction(attribute.IsolationLevel);

                        retMsg = _nextSink.SyncProcessMessage(msg);
                        IMethodReturnMessage methodReturn = retMsg as IMethodReturnMessage;
                        Exception exception = methodReturn.Exception;

                        if (exception != null)
                        {
                            dbTransaction.Rollback();
                        }
                        else
                        {
                            dbTransaction.Commit();
                        }
                        dbTransaction.Dispose();
                        dbTransaction = null;
                    }
                }
            }

            
            return retMsg;
        }
    }
}
